package com.powerbank.usercenter.service.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.powerbank.usercenter.dto.UserLoginDTO;
import com.powerbank.usercenter.dto.UserRegisterDTO;
import com.powerbank.usercenter.entity.User;
import com.powerbank.usercenter.entity.UserProfile;
import com.powerbank.usercenter.mapper.UserMapper;
import com.powerbank.usercenter.mapper.UserProfileMapper;
import com.powerbank.usercenter.service.AuthService;
import com.powerbank.usercenter.service.SmsService;
import com.powerbank.usercenter.utils.JwtUtils;
import com.powerbank.usercenter.utils.RedisUtils;
import com.powerbank.usercenter.vo.UserLoginVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;

/**
 * 用户认证服务实现
 */
@Slf4j
@Service
public class AuthServiceImpl implements AuthService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserProfileMapper userProfileMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private SmsService smsService;

    private static final String SMS_CODE_PREFIX = "sms:code:";
    private static final String USER_TOKEN_PREFIX = "user:token:";
    private static final int SMS_CODE_EXPIRE = 300; // 5分钟

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserLoginVO register(UserRegisterDTO registerDTO) {
        log.info("用户注册：{}", registerDTO.getPhone());

        // 验证短信验证码
        if (!verifySmsCode(registerDTO.getPhone(), registerDTO.getSmsCode(), "REGISTER")) {
            throw new RuntimeException("验证码错误或已过期");
        }

        // 检查手机号是否已注册
        User existUser = userMapper.selectByPhone(registerDTO.getPhone());
        if (existUser != null) {
            throw new RuntimeException("手机号已注册");
        }

        // 验证密码
        if (!registerDTO.getPassword().equals(registerDTO.getConfirmPassword())) {
            throw new RuntimeException("两次输入的密码不一致");
        }

        // 创建用户
        User user = new User();
        user.setPhone(registerDTO.getPhone());
        user.setUsername(generateUsername());
        user.setPassword(passwordEncoder.encode(registerDTO.getPassword()));
        user.setNickname(StrUtil.isNotBlank(registerDTO.getNickname()) ? 
                        registerDTO.getNickname() : "用户" + RandomUtil.randomString(6));
        user.setStatus(1); // 正常状态
        user.setRegisterSource(registerDTO.getRegisterSource());
        user.setCreatedTime(LocalDateTime.now());
        user.setUpdatedTime(LocalDateTime.now());

        userMapper.insert(user);

        // 创建用户档案
        UserProfile profile = new UserProfile();
        profile.setUserId(user.getId());
        profile.setUserLevel(1); // 普通用户
        profile.setCreditScore(new BigDecimal("100")); // 初始信用分100
        profile.setTotalOrders(0);
        profile.setTotalAmount(BigDecimal.ZERO);
        profile.setInviteCode(generateInviteCode());
        profile.setInvitedCount(0);
        profile.setLastActiveTime(LocalDateTime.now());
        profile.setCreatedTime(LocalDateTime.now());
        profile.setUpdatedTime(LocalDateTime.now());

        userProfileMapper.insert(profile);

        // 删除验证码
        redisUtils.delete(SMS_CODE_PREFIX + registerDTO.getPhone() + ":REGISTER");

        log.info("用户注册成功，用户ID：{}", user.getId());
        
        // 生成Token
        String accessToken = jwtUtils.generateToken(user.getId(), user.getUsername(), "USER");
        String refreshToken = jwtUtils.generateRefreshToken(user.getId(), user.getUsername(), "USER");

        // 保存Token到Redis
        redisUtils.set(USER_TOKEN_PREFIX + user.getId(), accessToken);

        // 构建返回对象
        UserLoginVO loginVO = new UserLoginVO();
        loginVO.setUserId(user.getId());
        loginVO.setUsername(user.getUsername());
        loginVO.setPhone(user.getPhone());
        loginVO.setNickname(user.getNickname());
        loginVO.setAccessToken(accessToken);
        loginVO.setRefreshToken(refreshToken);

        return loginVO;
    }

    @Override
    public UserLoginVO loginBySms(UserLoginDTO loginDTO) {
        log.info("用户短信登录：{}", loginDTO.getPhone());

        // 验证短信验证码
        if (!verifySmsCode(loginDTO.getPhone(), loginDTO.getSmsCode(), "LOGIN")) {
            throw new RuntimeException("验证码错误或已过期");
        }

        // 查询用户
        User user = userMapper.selectByPhone(loginDTO.getPhone());
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        if (user.getStatus() != 1) {
            throw new RuntimeException("用户已被禁用或锁定");
        }

        // 生成Token
        String accessToken = jwtUtils.generateToken(user.getId(), user.getUsername(), "USER");
        String refreshToken = jwtUtils.generateRefreshToken(user.getId(), user.getUsername(), "USER");

        // 保存Token到Redis
        redisUtils.set(USER_TOKEN_PREFIX + user.getId(), accessToken);

        // 更新最后登录信息
        userMapper.updateLastLoginInfo(user.getId(), 
                                     LocalDateTime.now().toString(), 
                                     "127.0.0.1"); // 这里应该获取真实IP

        // 构建返回对象
        UserLoginVO loginVO = new UserLoginVO();
        loginVO.setUserId(user.getId());
        loginVO.setUsername(user.getUsername());
        loginVO.setPhone(user.getPhone());
        loginVO.setNickname(user.getNickname());
        loginVO.setAccessToken(accessToken);
        loginVO.setRefreshToken(refreshToken);

        log.info("用户登录成功，用户ID：{}", user.getId());
        return loginVO;
    }

    @Override
    public UserLoginVO loginByPassword(UserLoginDTO loginDTO) {
        log.info("用户密码登录：{}", loginDTO.getPhone());

        // 查询用户
        User user = userMapper.selectByPhone(loginDTO.getPhone());
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        if (user.getStatus() != 1) {
            throw new RuntimeException("用户已被禁用或锁定");
        }

        // 验证密码
        if (!passwordEncoder.matches(loginDTO.getPassword(), user.getPassword())) {
            throw new RuntimeException("密码错误");
        }

        // 生成Token
        String accessToken = jwtUtils.generateToken(user.getId(), user.getUsername(), "USER");
        String refreshToken = jwtUtils.generateRefreshToken(user.getId(), user.getUsername(), "USER");

        // 保存Token到Redis
        redisUtils.set(USER_TOKEN_PREFIX + user.getId(), accessToken);

        // 更新最后登录信息
        userMapper.updateLastLoginInfo(user.getId(), 
                                     LocalDateTime.now().toString(), 
                                     "127.0.0.1"); // 这里应该获取真实IP

        // 构建返回对象
        UserLoginVO loginVO = new UserLoginVO();
        loginVO.setUserId(user.getId());
        loginVO.setUsername(user.getUsername());
        loginVO.setPhone(user.getPhone());
        loginVO.setNickname(user.getNickname());
        loginVO.setAccessToken(accessToken);
        loginVO.setRefreshToken(refreshToken);

        log.info("用户登录成功，用户ID：{}", user.getId());
        return loginVO;
    }

    @Override
    public UserLoginVO refreshToken(String refreshToken) {
        log.info("刷新Token");

        if (!jwtUtils.validateToken(refreshToken, "")) { // 简化验证
            throw new RuntimeException("刷新Token无效");
        }

        String username = jwtUtils.extractUsername(refreshToken);
        Long userId = jwtUtils.getUserIdFromToken(refreshToken);

        // 生成新的Token
        String newAccessToken = jwtUtils.generateToken(username);
        String newRefreshToken = jwtUtils.generateToken(username + "_refresh");

        // 更新Redis中的Token
        if (userId != null) {
            redisUtils.set(USER_TOKEN_PREFIX + userId, newAccessToken);
        } else {
            // 简化处理，实际应用中需要根据用户ID查找
            redisUtils.set(USER_TOKEN_PREFIX + "temp", newAccessToken);
        }

        UserLoginVO loginVO = new UserLoginVO();
        loginVO.setUsername(username);
        loginVO.setAccessToken(newAccessToken);
        loginVO.setRefreshToken(newRefreshToken);

        return loginVO;
    }

    @Override
    public void logout(Long userId) {
        log.info("用户登出，用户ID：{}", userId);
        redisUtils.del(USER_TOKEN_PREFIX + userId);
    }

    @Override
    public void blacklistToken(String token) {
        // 实现将Token加入黑名单的逻辑
        log.info("将Token加入黑名单: {}", token);
        // 这里可以将Token存储到Redis中，并设置过期时间
        // 例如：redisUtils.set("blacklist:token:" + token, "1", jwtUtils.getExpiration() / 1000);
    }

    @Override
    public String generateToken(Long userId, String username, String userType) {
        return jwtUtils.generateToken(userId, username, userType);
    }

    @Override
    public Long parseToken(String token) {
        // 实现解析Token获取用户ID的逻辑
        log.info("解析Token: {}", token);
        try {
            return jwtUtils.getUserIdFromToken(token);
        } catch (Exception e) {
            log.error("Token解析失败", e);
            return null;
        }
    }

    @Override
    public boolean verifyToken(String token) {
        log.info("验证Token");
        try {
            return jwtUtils.validateToken(token, "");
        } catch (Exception e) {
            log.error("Token验证失败", e);
            return false;
        }
    }

    @Override
    public void sendSmsCode(String phone, String type) {
        log.info("发送短信验证码：{}, 类型：{}", phone, type);

        String code = RandomUtil.randomNumbers(6);
        String key = SMS_CODE_PREFIX + phone + ":" + type;

        // 检查发送频率限制
        if (redisUtils.hasKey(key)) {
            throw new RuntimeException("验证码已发送，请稍后再试");
        }

        // 发送短信
        boolean success = smsService.sendCode(phone, code, type);
        if (!success) {
            throw new RuntimeException("短信发送失败");
        }

        // 保存验证码到Redis
        redisUtils.set(key, code, SMS_CODE_EXPIRE);
        log.info("短信验证码发送成功：{}", phone);
    }

    @Override
    public boolean verifySmsCode(String phone, String code, String type) {
        String key = SMS_CODE_PREFIX + phone + ":" + type;
        String savedCode = (String) redisUtils.get(key);
        
        if (savedCode == null || !savedCode.equals(code)) {
            return false;
        }

        // 验证成功后删除验证码
        redisUtils.del(key);
        return true;
    }

    @Override
    public void resetPassword(String phone, String smsCode, String newPassword) {
        // 验证短信验证码
        if (!verifySmsCode(phone, smsCode, "RESET_PASSWORD")) {
            throw new RuntimeException("验证码错误或已过期");
        }

        // 查询用户
        User user = userMapper.selectByPhone(phone);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        // 更新密码
        user.setPassword(passwordEncoder.encode(newPassword));
        user.setUpdatedTime(LocalDateTime.now());
        userMapper.updateById(user);

        log.info("用户密码重置成功: userId={}", user.getId());
    }
    private String generateUsername() {
        return "user_" + UUID.fastUUID().toString(true).substring(0, 8);
    }

    /**
     * 生成邀请码
     */
    private String generateInviteCode() {
        return RandomUtil.randomString("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 8);
    }
}